package com.markix.security.oauth2login;

import com.markix.dao.UserToAuthDao;
import com.markix.entity.UserToAuthPO;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Optional;

/**
 * @author markix
 * @date 2022/9/2 17:12
 */
public class OAuth2LoginAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

    private UserToAuthDao userToAuthDao;
    private UserDetailsService userDetailsService;
    private ClientRegistrationRepository clientRegistrationRepository;

    public OAuth2LoginAuthenticationSuccessHandler(UserToAuthDao userToAuthDao,
                                                   UserDetailsService userDetailsService,
                                                   ClientRegistrationRepository clientRegistrationRepository) {
        super();
        this.userToAuthDao = userToAuthDao;
        this.userDetailsService = userDetailsService;
        this.clientRegistrationRepository = clientRegistrationRepository;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
        // 1.三方用户未被绑定，且当前有登录用户，直接绑定，跳主页，提示绑定成功（绑定操作）
        // 2.三方用户未被绑定，且当前无登录用户，跳绑定页面（登录&绑定操作）
        // 3.三方用户已被绑定，找到用户直接登录，跳主页（三方登录操作）

        OAuth2AuthenticationToken oauth2Auth = (OAuth2AuthenticationToken) authentication;

        String authorizationUri = clientRegistrationRepository.findByRegistrationId(oauth2Auth.getAuthorizedClientRegistrationId()).getProviderDetails().getAuthorizationUri();
        String type = ThirdPlatformType.parse(authorizationUri).toString();
        String identity = authentication.getName();
        Optional<UserToAuthPO> bind = userToAuthDao.findByTypeAndIdentity(type, identity);

        // 1.三方用户未被绑定，且当前有登录用户，直接绑定，返回success，跳主页
        if(!bind.isPresent() && TempAuthContext.notEmpty()){
            // 还原已登录用户的认证信息
            Authentication auth = TempAuthContext.get();
            SecurityContextHolder.getContext().setAuthentication(auth);
            String username = auth.getName();
            // 绑定
            userToAuthDao.save(new UserToAuthPO().setType(type).setIdentity(identity).setUserId(username).setTime(LocalDateTime.now().toString()));

            getRedirectStrategy().sendRedirect(request, response, WebAttributes.bindSuccess);
            return;
        }

        // 2.三方用户未被绑定，且当前无登录用户，跳绑定页面
        if(!bind.isPresent() && !TempAuthContext.notEmpty()){
            // 将三方认证信息先存起来，以便用户登录后绑定
            HttpSession session = request.getSession(true);
            session.setAttribute(WebAttributes.THIRD_TYPE, type);
            session.setAttribute(WebAttributes.THIRD_AUTHENTICATION, SecurityContextHolder.getContext().getAuthentication());
            // 置空三方认证信息，防止它存到session去（HttpSessionSecurityContextRepository.SaveToSessionResponseWrapper.saveContext）
            SecurityContextHolder.getContext().setAuthentication(null);
            // 跳绑定页面
            getRedirectStrategy().sendRedirect(request, response, WebAttributes.bindPage);
            return;
        }

        // 3.三方用户已被绑定，找到用户直接登录，跳主页
        String username = bind.get().getUserId();
        UserDetails user = userDetailsService.loadUserByUsername(username);
        UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(user, authentication.getCredentials(), user.getAuthorities());
        result.setDetails(authentication.getDetails());
        SecurityContextHolder.getContext().setAuthentication(result);

        getRedirectStrategy().sendRedirect(request, response, WebAttributes.oauth2LoginSuccess);

        clearAuthenticationAttributes(request);
    }


}
